package com.example.skytakeoutserver.config

import com.example.serverbase.ext.Log
import com.example.skytakeoutserver.handler.JwtWebFilter
import io.swagger.v3.oas.models.OpenAPI
import io.swagger.v3.oas.models.info.Info
import org.springdoc.core.models.GroupedOpenApi
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.security.reactive.PathRequest
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.core.Ordered
import org.springframework.core.annotation.Order
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.SecurityWebFiltersOrder
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
import org.springframework.security.crypto.password.PasswordEncoder
import org.springframework.security.web.server.SecurityWebFilterChain
import org.springframework.security.web.server.util.matcher.PathPatternParserServerWebExchangeMatcher


/**
 * todo:
 */
@Configuration
@EnableWebFluxSecurity
class MultiSecurityHttpConfig {

    companion object {
        val MY_OWN_PACKAGE = "com.example.skytakeoutserver"
        val MY_OWN_PACKAGE_CONTROLLRR = "com.example.skytakeoutserver.controller"
    }

    /**
     * 密码加密
     * @Bean 注解用于定义由 Spring 容器管理的 Bean。它是方法级别的注解，
     * 通常与 @Configuration 注解一起使用，以便在 Java 配置期间执行该方法，
     * 并将其返回值注册为 BeanFactory 中的 Bean
     */
    @Bean
    fun passwordEncoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }


    /**
     *
     */
    @Order(Ordered.HIGHEST_PRECEDENCE)
    @Bean
    fun apiHttpSecurity(http: ServerHttpSecurity, adminJwtWebFilter: JwtWebFilter): SecurityWebFilterChain {
        return http.apply {
            securityMatcher(
                PathPatternParserServerWebExchangeMatcher("/admin/**")
            )
            securityMatcher(
                PathPatternParserServerWebExchangeMatcher("/api/**")
            )

            authorizeExchange {
                //it.authorize(anyExchange, authenticated)
                it.pathMatchers(
                    "/admin/employee/login",
                    "/notify",
                    "/user/user/login",
                    "/user/shop/status",
                    "/v3/swagger-ui.html", // 保留你原来的放行规则
                    "/swagger-ui/**", // 放行Swagger UI的所有资源
                    "/v3/api-docs/**", // 放行API文档
                    "/swagger-resources/**", // Swagger的资源文件
                    "/webjars/**", // Swagger UI的webjars资源,
                    "/v3/doc.html",
                    "/ws/**"
                ).permitAll()
                // 放行所有的静态资源
                it.matchers(
                    PathRequest.toStaticResources()
                        .atCommonLocations()
                ).permitAll()
                it.anyExchange().authenticated()
            }
            addFilterAt(adminJwtWebFilter, SecurityWebFiltersOrder.FIRST)
            //oauth2ResourceServer {
            //    it.jwt { }
            //}
            csrf { it.disable() }
            formLogin { it.disable() }
            httpBasic { it.disable() }
            logout { it.disable() }

        }.build()

    }

    /**
     * 管理员开放api
     */
    @Bean
    fun adminOpenApi(
        @Value("\${springdoc.version}")
        appVersion: String?
    ): GroupedOpenApi {
        val paths = arrayOf("/admin/**")
        val packagedToMatch = arrayOf("${MY_OWN_PACKAGE}.controller.admin")
        Log.info("adminOpenApi: {}", packagedToMatch)

        return GroupedOpenApi.builder().group("admin")
            .addOpenApiCustomizer { openApi: OpenAPI ->
                openApi.info(
                    // Swagger
                    Info().title("管理端API").version(appVersion)
                )
            }
            .pathsToMatch(*paths).packagesToScan(*packagedToMatch)
            .build()
    }

    /**
     * 用户开放api
     */
    @Bean
    fun userOpenApi(@Value("\${springdoc.version}") appVersion: String?): GroupedOpenApi {
        val paths = arrayOf("/user/**")
        val packagedToMatch = arrayOf("${MY_OWN_PACKAGE}.controller.user")
        Log.info("userOpenApi: {}", packagedToMatch)

        return GroupedOpenApi.builder().group("user")
            .addOpenApiCustomizer { openApi: OpenAPI ->
                openApi.info(
                    Info().title("Stream API").version(appVersion)
                )
            }
            .pathsToMatch(*paths)
            .packagesToScan(*packagedToMatch)
            .build()
    }


}